package com.jiao.comm;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.file.FileNameUtil;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 包扫描.
 * @Author: vincent.jiao
 * @Date: 2021/6/11
 */
public class PackageScann {
    private static Map<Resource, Class> resourceClassMap = new ConcurrentHashMap<>();

    /**
     * 返回所有符合条件的资源.
     * @param path 路径(支持正则)
     * @return
     * @throws IOException
     */
    public static Resource[] scann(String path) throws IOException {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        return resolver.getResources(path);
    }

    /**
     * 扫描所有class.
     * @param path
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static List<Class> scannClass(String path)
            throws IOException, ClassNotFoundException {

        Resource[] resources = scann(path);
        if (resources == null || resources.length == 0){
            return Collections.emptyList();
        }

        ClassLoader loader = ClassLoader.getSystemClassLoader();
        List<Class> classList = new LinkedList<>();
        CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();

        for (Resource resource : resources) {
            Class valClass = resourceClassMap.get(resource);
            if (resource.exists() && resource.getFile().isFile()){
                if (valClass == null && "class".equals(FileNameUtil.extName(resource.getFile()))){
                    MetadataReader reader = cachingMetadataReaderFactory.getMetadataReader(resource);
                    String className = reader.getClassMetadata().getClassName();
                    try {
                        valClass = loader.loadClass(className);
                    }catch (ClassNotFoundException e) {
                        valClass = Class.forName(className);
                    }
                    resourceClassMap.put(resource, valClass);
                }

                classList.add(valClass);
            }
        }

        return classList;
    }

    /**
     * 扫描指定包下存在指定注解.
     * @param path
     * @param annoClass 注解的class
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static List<Class> scannByAnno(String path, Class annoClass)
            throws IOException, ClassNotFoundException {

        List<Class> classList = scannClass(path);
        if (CollectionUtil.isEmpty(classList)){
            return Collections.emptyList();
        }

        List<Class> valueList = new LinkedList<>();
        for (Class item : classList) {
            if (item.getAnnotation(annoClass) != null){
                valueList.add(item);
            }
        }

        return valueList;
    }

    //TODO 待删除
    public static void main(String[] arsg) throws IOException, ClassNotFoundException {
//        List<Class> list =
//                scannByAnno("classpath:com/sharding/entity/**/*.class", TableCache.class);
//
//        System.out.println(list);
    }
}
